{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 构造哈密顿量\n",
    "\n",
    "*版权所有 (c) 2021 百度量子计算研究所，保留所有权利。*\n",
    "\n",
    "## 内容概要\n",
    "\n",
    "本教程介绍如何使用量脉（Quanlse）快速地构造哈密顿量。本教程的大纲如下：\n",
    "\n",
    "- 背景介绍\n",
    "- 准备工作\n",
    "- 定义系统哈密顿量\n",
    "- 添加控制脉冲波形\n",
    "- 模拟演化和辅助工具\n",
    "- 总结"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 背景介绍\n",
    "\n",
    "一般地，在超导量子系统中，系统的哈密顿量 $\\hat{H}_{\\rm sys}(t)$ 用于描述整个量子系统的总能量:\n",
    "\n",
    "$$\n",
    "\\hat{H}_{\\rm sys}(t) = \\hat{H}_{\\rm drift} + \\hat{H}_{\\rm coup} + \\hat{H}_{\\rm ctrl}(t).\n",
    "$$\n",
    "\n",
    "它通常包含三个项：描述系统中单个量子比特的漂移项 $\\hat{H}_{\\rm drift}$、描述量子比特相互作用的耦合项 $\\hat{H}_{\\rm coup}$ 和描述控制场的控制项 $\\hat{H}_{\\rm ctrl}(t)$。其中，漂移项和耦合项通常与时间无关，而控制项则通常是与时间相关的函数。\n",
    "\n",
    "当哈密顿量构造完成后，我们可以通过求解海森堡绘景 (Heisenberg picture) 中的薛定谔方程来模拟量子系统的演化，从而得到时序演化算符 $U$：\n",
    "\n",
    "$$\n",
    "i\\hbar\\frac{{\\rm \\partial}U(t)}{{\\rm \\partial}t} = \\hat{H}(t)U(t).\n",
    "$$\n",
    "\n",
    "我们在量脉中提供了多种函数和预定义算符，使用户能够轻松地构造复杂量子系统的哈密顿量。\n",
    "\n",
    "\n",
    "## 准备工作 \n",
    "\n",
    "成功安装量脉后，您可以按照本教程运行下面的量脉程序来学习量脉是如何构造哈密顿量的。在运行此教程前，您需要从量脉和常用的 Python 库 `math` 分别导入必要的包和常数 $\\pi$ ："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from Quanlse.QHamiltonian import QHamiltonian as QHam\n",
    "from Quanlse.QOperator import number, driveX, driveY, duff\n",
    "from Quanlse.QWaveform import gaussian, dragY1\n",
    "\n",
    "from math import pi"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 定义哈密顿量\n",
    "\n",
    "在这一节中，我们将以由两个三能级量子比特组成的超导量子系统为例，演示如何用量脉构造哈密顿量。首先，我们将分别添加与时间无关的漂移项和耦合项，以及与时间有关的控制项来定义系统哈密顿量。\n",
    "\n",
    "首先我们从 `QHam` 类中实例化一个对象 `ham` ， `ham` 中包含了系统的基本信息。它的参数包括量子比特数（即子系统个数）`subSysNum` 、系统能级 `sysLevel`以及采样时间 `dt`（以纳秒为单位）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ham = QHam(subSysNum=2, sysLevel=3, dt=1.0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在量脉 2.0 版本中，`QHam` 支持用户为系统中不同的量子比特设置不同的能级。用户可以将量子比特的能级作为一个 `List` 传递给 `sysLevel`。例如，当 `subSysNum=2` 时，我们可以将 `[2，10]` 传递给 `sysLevel` 来定义一个 'qubit 0' 的能级为2， 'qubit 1' 的能级为10的系统。这个系统处于一个20维的空间$\\mathcal{H}^{2}\\otimes\\mathcal{H}^{10}$ 中（其中$\\mathcal{H}^n$ 表示 $n$ 维希尔伯特空间）。\n",
    "\n",
    "然后，我们定义系统漂移哈密顿量，主要包括频率失谐项和高能级的非谐项：\n",
    "$$\n",
    "\\hat{H}_{\\rm drift} = \\sum_{i=0}^1(\\omega_i-\\omega_d)\\hat{a}_i^\\dagger \\hat{a}_i + \\sum_{i=0}^1 \\frac{\\alpha_i}{2} \\hat{a}_i^{\\dagger}\\hat{a}_i^{\\dagger}\\hat{a}_i\\hat{a}_i.\n",
    "$$ \n",
    "\n",
    "我们可以使用 `addDrift()` 将漂移哈密顿量添加到前面构造的系统哈密顿量 `ham` 中。如下面代码所示，我们传入相应的参数和在 `QOperator` 模块中预定义的算符的矩阵（[点击这里](https://quanlse.baidu.com/api/Quanlse/Quanlse.QOperator.html)查看所有预定义的算符）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# The qubit frequency for the qubits, GHz * 2 * pi\n",
    "wq = [4.887 * (2 * pi), 4.562 * (2 * pi)]  \n",
    "\n",
    "# Anharmonicity for the qubits, GHz * 2 * pi\n",
    "anharm = [- 0.317 * (2 * pi), - 0.317 * (2 * pi)]\n",
    "\n",
    "# The drive pulse is in resonance  \n",
    "wd = wq[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "由于这个系统中有两个量子比特，我们可以使用 `for` 循环语句来添加漂移项。其中，第一个参数是一个算符，它是 `Qoperator` 中已经预先定义好的对象，用户使用时只需要传入维度参数即可；`onSubSys` 表示该漂移项添加到哪个量子比特上；`coef` 是该漂移项的系数；`name` 是用户自定义的名称。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Add drift terms to the Hamiltonian\n",
    "for q in range(2):\n",
    "    ham.addDrift(number, onSubSys=q, coef=wq[q] - wd, name='number%d' % q)\n",
    "    ham.addDrift(duff, onSubSys=q, coef=anharm[q] / 2, name='duff%d' % q)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "接下来，我们添加描述量子比特之间相互作用的耦合项。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 添加耦合项\n",
    "这里，耦合项可以写成：\n",
    "$$\n",
    "\\hat{H}_{\\rm coup} = \\frac{g_{01}}{2} (\\hat{a}_0\\hat{a}_1^\\dagger + \\hat{a}_0^\\dagger \\hat{a}_1).\n",
    "$$ \n",
    "\n",
    "在量脉中，只需要一行代码就可以添加耦合项——使用函数 `addCoupling()`，选择想要添加的量子比特的索引并指定耦合强度 `g` 。注意参数 `g` 是耦合项前面的那一整个系数，所以我们在定义时不要忘记那个常数 $1/2$ 。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ham.addCoupling(onSubSys=[0, 1], g=0.0277 * (2 * pi) / 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "最后，我们需要添加系统的控制项。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## 添加控制脉冲波形\n",
    "在超导量子系统中，控制哈密顿量表示施加在量子比特上的外部控制（微波、磁通量等）。如果我们想对量子比特 0 应用 X 和 Y 轴方向的控制，则相应的控制项是：\n",
    "$$\n",
    "\\hat{H}_{\\rm ctrl} = A_0^x(t)\\frac{\\hat{a}_0+\\hat{a}_0^\\dagger}{2} + iA_0^y(t)\\frac{\\hat{a}_0-\\hat{a}_0^\\dagger}{2}. \n",
    "$$\n",
    "在我们定义了整个量子系统的哈密顿量之后，我们可以在控制项中加入一个特定的波形来实现具体的量子操作。在量脉中，可以使用 `addWave()` 方法定义波形，同时用户可以使用 `clearWaves()` 方法清除指定控制项中所有的波形。\n",
    "\n",
    "在这里，我们以 `addWave()` 方法为例介绍如何定义控制波形。每个波形函数 $A(t)$ 可以用四个参数来定义：起始时间 `t0`、持续时间 `t` 和相应的波形参数 `a` 、`tau` 、`sigma` 。函数 `addWave()` 允许我们以两种不同的方式设置波形：\n",
    "\n",
    "- **使用预设的波形函数:**\n",
    "用户可以调用预置的波形函数，这里我们使用 `gaussian` 高斯波。支持的波形详见 [API](https://quanlse.baidu.com/api/Quanlse/Quanlse.QWaveform.html).\n",
    "\n",
    "```python\n",
    "ham.addWave(driveX(3), onSubSys=0, waves=gaussian(t0=0, t=20, a=1.1, tau=10, sigma=4), name = 'q0-ctrlx')\n",
    "```\n",
    "\n",
    "- **使用用户自定义的波形函数:**\n",
    "用户还可以以 `func(_t, args)` 的形式自定义波形函数，其中第一个参数 `_t` 是持续时间，`args` 是相关的波形参数，示例如下：\n",
    "\n",
    "```python\n",
    "def userWaveform(t0: Union[int, float], t: Union[int, float], a: float, tau: float, sigma: float,\n",
    "             omega: float = None, phi: float = None) -> QWaveform:\n",
    "    \"\"\"\n",
    "    Return a QWaveform object of user-defined wave.\n",
    "    \"\"\"\n",
    "\n",
    "    def func(_t, args):\n",
    "        _a, _tau, _sigma = args\n",
    "        if _sigma == 0:\n",
    "            return 0\n",
    "        pulse = _a * exp(- ((_t - _tau) ** 2 / (2 * _sigma ** 2)))\n",
    "        return pulse\n",
    "\n",
    "    wave = QWaveform(f=func, t0=t0, t=t, args=(a, tau, sigma), freq=freq, freqphi)\n",
    "    wave.name = \"user-defined wave\"\n",
    "    return wave\n",
    "ham.addWave(driveX(3), onSubSys=0, waves=userWaveform(t0=0, t=20, a=1.1, tau=10, sigma=4), name = 'q0-ctrlx')\n",
    "```\n",
    "\n",
    "在本例中，我们将预定义的高斯波形以及 DRAG 脉冲分别添加到 X 和 Y 控制项中："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ham.appendWave(driveX, onSubSys=0, waves=gaussian(t=20, a=1.1, tau=10, sigma=4))\n",
    "ham.appendWave(driveY, onSubSys=0, waves=dragY1(t=20, a=1.7, tau=10, sigma=4))\n",
    "ham.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 模拟演化和辅助工具\n",
    "\n",
    "在定义了哈密顿量和控制波形后，我们可以使用内置的模拟函数 `simulate()` 来计算该系统的时序演化算法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "results = ham.simulate()\n",
    "print(results.result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们还可以使用 python 库函数 `print()` 可视化哈密顿量的详细信息："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(ham)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "另外地，我们能够通过 `job` 中的 `getPulseSequences()` 提取控制项的波形幅值序列："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(ham.job.generatePulseSequence(driveY, 0))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 总结\n",
    "\n",
    "本教程旨在介绍如何使用量脉构造系统哈密顿量并对其进行模拟及可视化。在阅读此教程后，用户可以通过这个链接 [tutorial-construct-hamiltonian.ipynb](https://github.com/baidu/Quanlse/blob/main/Tutorial/CN/tutorial-construct-hamiltonian-cn.ipynb) 跳转到此 Jupyter Notebook 文档对应的 GitHub 页面获取相关的代码，尝试不同于本教程示例给出的参数值或函数以获得更深的理解。"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "2a31ed61199c5c13a03065ecec963a63da8631d96d1b9e695dac4715cb4eadb9"
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
